//
//  computer.hpp
//  DataStructure
//
//  Created by 劢克科技 on 2020/9/22.
//  Copyright © 2020 Shuleiming. All rights reserved.
//

#ifndef computer_hpp
#define computer_hpp

#include <stdio.h>

// ***** 计算机的发展 *****
// 1.电子管：穿孔卡片
// 2.晶体管：穿孔卡片、磁带
// 3.集成电路：磁带、磁盘

// ***** 计算机硬件的基本组成 *****
// ✨冯诺依曼机
//       存储器
// 输入   运算器     输出
//       控制器
// 1.以运算器为中心
// 2.存储程序的开端

// 现代计算机
// 以存储器为中心

// CUP：运算器+控制器
// 主机：CUP+主存

// ***** 硬件的各个部件 *****
// 主存储器：存储体+MAR+MDR（内存）
// 存储单元：用于存储二进制的单元
// 存储字：存储单元里的二进制
// 存储字长：存储单元二进制的位数

// MAR反映存储单元的个数
// MDR反映存储字长

// 运算器：实现算术运算和逻辑运算
// ACC+MQ+X+ALU
// ACC：累加器
// MQ：乘商寄存器
// X：通用寄存器
// ALU：算数逻辑单元（核心）

// 控制器：CU+IR+PC
// CU：控制单元（核心）：执行指令
// IR：指令寄存器：分析指令
// PC：程序寄存器：取指令

// ✨程序运行的过程

// ***** 计算机系统的层次结构 *****

// M4：高级语言机器
// M3：汇编语言机器
// M2：操作系统机器（提供系统调用）
// M1：传统机器（执行机器语言）
// M0：微程序及其（执行微指令）

// 编译程序：将高级语言编译一次性为机器语言
// 解释程序：解释一条指令，运行一条指令
// 机器语言：二进制代码，计算机可以直接运行

// 编译程序：将高级语言一次性翻译成机器语言
// 汇编程序：将汇编语言翻译成机器语言
// 解释程序：将高级语言一条一条翻译成机器语言

// ***** ✨性能指标 *****
// 主存储器容量：
// 存储单元个数 * 存储字长 b = 存储单元个数 * 存储字长 / 8B
/**
 MAR32位，MDR8位算总容量
 2^32 * 8 = 2^35b = 2^32B = 4GB
 */

// CPU性能
// 2.9GHz：脉冲信号的震荡频率
// CPU主频 = 1 / (cup时钟周期) (Hz)
// CPI:每条指令需要多少时钟周期
// 执行一条指令耗时：CIP * CPU时钟周期
/**
 CPU主频为1000Hz，某程序包含100条指令，CPI=3，需要多长时间执行完毕？(CPU执行时间)
 1/1000 * 3 * 100 = 0.3s
 */
// IPS：每秒执行多少指令 = CPU主频 / CPI
// FLOPS：每秒可以执行多少次浮点操作
// K=10^3,M=10^6,G=10^9,T=10^12

// 数据通路带宽：一次传输的数据量
// 吞吐量：单位时间内请求数量
// 响应时间

// 基准程序“跑分软件”

/**
 主频高的CPU一定比主频低的CPU快吗？
 不一定，和CPI也有关
 
 如果平均CPI相同，主频高的CPU一定比主频低的CPU快吗？
 也不一定，还要看指令系统，如果A不支持乘法运算（用加法代替），那么计算乘法时A就不一定比B快
 
 基准程序越快，说明性能越好吗？
 不一定，语句存在频度差异
 */


// ***** 进位计数制 *****
// 基数：每个数码位用到的符号个数
// 二进制基数：2
// 八进制基数：8...

// 二进制转8进制
// 3位一组转换

// 二进制转16进制
// 4位一组转换

// X01111、1111H（16进制）1111D（10进制）

// 十进制 -> 二进制
// 整数部分一直除2取余数
// 小数部分乘2，取小数再乘2...取整数部分
/**
 75.3 = 1001011.01001...
 */

// ***** BCD码 *****
// Binary Code Decimal:
// 使用二进制编码表示十进制数（4位二进制表示）

// ✨8421码
// 985 => 1001 1000 0101
/**
 8421码加法
 5+8=13
 0101 + 1000 = 1101(8421码无定义则+6)
 1101 + 0110 = 0001 0011 (1 3)
 
 9+9
 1001 + 1001 = 1 0010(8421码无定义则+6)
 10010 + 0110 = 0001 1000(1 8)
 */

// 余3码
// 8421码+(0011)

// 2421码
// 0-4 开头都是0
// 5-9 开头都是1

// 2421码和8421码都是有权的
// 余3码无权

// ***** 字符和字符串 *****
// 2^7 = 128个ASCII码
// 可印刷字符：32~126；其余为控制和通信字符
// tips：数字：48~57：0011 0000 ~ 0011 1001 （前四位相同，后四位为BCD码）
/**
 A的ASCII码是65，H存在存储单元M中，M中的内容是什么？
 H = 72 = 0100 1000
 */

// GB 2312-80：汉字+各种符号7445个（94*94矩阵）（2字节）
// 区码+位码：+20H（国标码，解决通信问题）；+80H（汉字内码，兼容ASCII码）

// 输入编码：拼音输入
// 输出：汉字字形码（像素点）

// 字符串
// ”abc“：占3字节+'\0'
// ”啊“：B0H + A1H
// “啊“：B0H + A1H + 00H（大端模式）
// “啊“：A1H + B0H + 00H（小端模式）

// ***** 奇偶校验码（d=2） *****
// 码字：若干位组成一个字（合法码字和非法码字）
// 码字距离：两个码字不同的位数
// 码距d：一种编码方案可能有若干码字，码字的最小距离成为“码距”
// d=1无检错能力；d=2有检错能力；d=3时可能有纠错能力

// 奇校验码：1的个数为奇数
// 偶校验码：1的个数为偶数

// 异或（模2加）：同0异1
// 硬件求偶校验位：每一位依次异或
// 硬件进行偶校验：每一位依次异或，=0对；=1错

// ***** ✨海明校验码 *****
// 思路：多个偶校验
// 信息位：n，校验位：k
// 2^k >= n + k + 1
/**
 1.求k
 信息位：1010，校验位：k=3（插入2^i-1）
 
 2.插入校验位
 101x0xx
 
 3.求校验位的值
 111 110 101 100 011 010 001
 1     0     1     x3   0    x2    x1
           1**       *1*   **1
 x1管理：1 3 5 7: x011
 x2管理：2 3 6 7: x001
 x3管理：4 5 6 7: x101
 x1=0,x2=1,x3=0（偶校验）
 完整海明码：1010010
 
 4.验证
 接收到1010010
 x1管理：1 3 5 7: 0011✅
 x2管理：2 3 6 7: 1001✅
 x3管理：4 5 6 7: 0101✅
 
 接收到1010000
 x1管理：1 3 5 7: 0011✅
 x2管理：2 3 6 7: 0001❌
 x3管理：4 5 6 7: 0101✅
 x3 x2 x1
 0    1   0 = 2
 */
// 补充：
// 海明码检错能力2位
// 海明码纠错能力1位
// 需要在添加一位全校验位，进行整体偶校验
// 发现错误且偶校验失败，可以纠错
// 发现错误且偶校验成功，说明发生2位错误，重传

// ***** ✨CRC循环冗余校验码 *****
// 思想：882 / 7 = 126 ... 0

/**
 信息码：101001，校验码：1101，校验码位数：3
 加0：101001 000，模2除法
 FCS（余数）：001
 CRC校验码：101001001
  */

// ***** ✨定点数的表示 *****
// 定点数 VS 浮点数
// 小数点不变 VS 小数点位置不固定（科学计数法）

// 无符号数：全部表示数值，并没有正负号
// 表示范围：8位可表示0~2^8-1（2^8个）

// 有符号数的定点表示
// 最高位：0正，1负

// 原码（0有两种表示形式）
// 符号位 + 数值部分
// 表示范围：8位可以表示：-(2^7-1) ~ 2^7-1（2^8-1个）
// 原码表示定点小数：-(1-2^(-7)) ~ 1-2^(-7) (2^8-1个)

// 反码（过渡）（0有两种表示形式）
// 若符号位为0，反码 = 原码
// 若符号位为1，反码：原码取反
// 表示范围和原码相同

// 补码（只有全0才表示0）
// 若符号位为0，补码 = 原码
// 若符号位为1，补码 = 反码+1（考虑进位）
// 1.0000000 = -1
// 10000000 = 2^-7
// 表示整数范围：-2^7 ~ 2^7-1 (2^8个)（100 表示 -4，000 表示 0）
// 定点小数范围： -1 ~ 1-2^(-7) (2^8个)

// 负数的补码转原码：取反+1

// 移码（只有全0才表示0）（只能表示整数）
// 补码符号位取反
// 表示范围和补码一致

/**
 定点数50，用8位原码，反码，补码，移码表示
 1 2 4 8 16 32 64
 原码、反码、补码：0011 0010
 移码：1011 0010
 
 定点数-100，用8位原码，反码，补码，移码表示
 原码：1110 0100
 反码：1001 1011
 补码：1001 1100
 移吗：0001 1100
 
 求真值
 [x]原=1000 1101
 [x]反=1000 1101
 [x]补=1000 1101
 [x]移=1000 1101
 
 x1=-13
 x2=1111 0010原 = -(2+16+32+64)=-114
 x3=1111 0011原=-115
 x4=0000 1101补、原=13
 */

// 技巧
// [x]补 转 [-x]补：符号位、数值位取反，末位+1

// ***** ✨码的作用 *****

// 减法变加法：加补数后取模
// 补码方便加减法，移码方便比较大小

// ***** 移位运算 *****

// 算数移位
// 原码（补0）
// 算数右移：相当于除以基数
// 算数左移：相当于乘以基数

// 反码（正数和原码一样）
// 负数的反码补1

// 补码
// -20D：1001 0100（原）
// -20D：1110 1011（反）
// -20D：1110 1100（补）
// 右移：补1
// 左移：补0

// 逻辑移位
// 右移：高位补0，左移：低位补0
// 可以看做”无符号数“的移位

// 循环移位
// 像”轮播图“循环移动

// 大端：先存放高字节，后存放低字节
// 小端：先存放低字节，后存放高字节

// ***** 加减运算&溢出判断 *****
/**
 设机器字长为8，A=15，B=-24，C=124求[A+B]补、[A-B]补、[A+C]补、[B-C]补
 [A]补 = 0000 1111
 [B]补 = 1001 1000 = 1110 0111 = 1110 1000
 [C]补 = 0111 1100
 [-C]补 = 1111 1100 = 1000 0011 = 1000 0100
 1110 1000
 1000 0100
 0110 1100
 [A+B]补 = 0000 1111 + 1110 1000 =1111 0111 = 1111 0110 = 1000 1001 =  -9
 [A-B]补 = 0000 1111 + 0001 1000 = 0010 0111 = 39
 [A+C]补 = 0000 1111 + 0111 1100 = 1000 1011 = 1000 1010 = 1111 0101 = -117（溢出）
 [B-C]补 = 1110 1000 + 1000 0100 = 0110 1100 = 108（溢出）
 */

// 溢出判断
// 下溢 | 负数 | 0 | 正数 | 上溢
// 正+正才会上溢 -- 正+正 = 负
// 负+负才会下溢 -- 负+负 = 正

// 方法一：正正负 || 负负正
// V = AB(!S) + (!A)(!B)S
// A、B为加数符号，S为结果符号、+代表或
// V = 0无溢出、V = 1有溢出

// 方法二：
// 符号位的进位Cs、最高位进位C1
// Cs（第9位）   C1（第8位）
// 0           1            上溢
// 1           0            下溢
// V = Cs 异或 C1

// 方法三：
// ✨双符号位：正（00），负（11）
// V = 符号位异或

// 符号扩展
// int -> long（1B -> 2B）
// 正整数：在前边添加8个0

// 负整数原码：在符号位后添加8个0
// 负整数反码：在符号位后添加8个1
// 负整数补码：在符号位后添加8个1

// 正小数：在后边添加8个0
// 负小数原码：在后面添加8个0
// 负小数反码：在后面添加8个1
// 负小数补码：在后面添加8个0

// ***** ✨原码乘法思想 *****
// 逻辑右移，移动n位，取绝对值运算
// 原码乘法实现方法：先加法，再右移（✨符号位不参与运算和移动），最后确定符号位
// ACC MQ（乘数）
// X（被乘数） （ACC = MQ * X）
// -0.1101 * 0.1011 = -0.10001111

// ***** 补码乘法思想 *****

// 算术右移，移动n+1位（✨符号位也参与计算但是不移动），直接放入运算
// ACC（双符号） MQ+辅助位（单符号）
// X（双符号） （ACC = MQ * X）
// 辅助位-MQ最低位=1时，ACC+[x]补
// 辅助位-M Q最低位=0时，ACC+0
// 辅助位-MQ最低位=-1时，ACC+[-x]补
// -0.1101 * 0.1011 = -0.10001111

// ***** 原码除法 *****

// 恢复余数法
// 取绝对值运算、最后确定符号
// ACC(被除数) MQ（商）
// X（除数）
// 恢复余数法：
// 先商1，若ACC-X<0，ACC恢复后改为商0
// 逻辑左移，移动n位

// ✨加减交替法（不恢复余数）
// 若ACC-X<0，下一步左移后加除数商0
// 若ACC-X>0，下一步左移后减除数商0

// ***** ✨补码除法 *****
// 双符号位运算
// 被除数和除数：同号减、异号加
// 余数和除数：同号商1左移减除数；异号商0左移加除数
// 最后一位商1

// ***** C语言强制转换 *****
// 有符号转换成无符号数：不改变内容，改变解析方式
// 长类型转为短类型：高位截短，低位保留
// 短类型转为长类型：高位拓展（填0或1）

// ***** 数据存储和排列 *****
// 大端方式：符合人类阅读
// 小端方式：符合机器处理

// 字地址逻辑左移2位 = 字节地址 （字*4 = 字节）
// 半字地址逻辑左移1位 = 字节地址 （半字*2 = 字节）

// 边界对齐：牺牲空间换时间

// ***** 浮点数的表示 *****
// 定点数的局限性：表示范围有限
// 科学计数法：+11+3.026 （阶码&尾数）
// N = r^E * M (r通常为2，E表示小数点位置，M表示精度)

/**
 补码表示阶码和尾数
 a = 001; 1.1001
 b = 010; 0.01001

 a = -0.0111 * 2 = -0.111
 b = 0.01001 * 2^2 = +1.001
 ------------------------------------
 a = 010; 00.1100, b = 010; 00.1000, a+b =
 2^2*(00.1100 + 00.1000)
 =2^2*01.0100
 =2^3*00.10100 (规格化)
 =011;00.10100
 */
// 原码规格化
// 正数规格：0.1xxxx
// 正数尾数范围：1/2 <= M <= 1-2^(-n)
// 负数规格：1.1xxxx
// 负数尾数范围：-(1-2^(-n)) <= M <= -1/2

// 补码规格化
// 正数规格：0.1xxxx
// 正数尾数范围：1/2 <= M <= 1-2^(-n)
// ✨负数规格：1.0xxxx
// 负数尾数范围：-1<= M <= -(1/2+2^-n)

/**
 0110; 1.1110100规格化
 0011;1.0100000 （补码负数规格1.0xxxx，左移3位）
 */

// ***** ✨浮点数标准IEEE 754 *****
// 移码 = 补码符号位取反
// 移码 = 真值 + 偏置值 (2^(n-1) - 1)
// /Users/meckey/Gitee/DataStructure/images/1.png

/**
 IEEE754 [-127]移码和[-128]移码
 [-127] = -0111 1111 + 0111 1111 = 0000 0000
 [-128] = -1000 0000 + 0111 1111 = 1111 1111
 */
// IEEE阶码用移码表示，尾数用原码表示
// IEEE754 尾数23位，实际表示24位（隐藏位是1）
// 8位的阶码表示范围：-126~127
// 阶码全0，尾数不为全0，表示非规格化小数：阶码=-127，尾数的隐藏位为0
// 阶码全0，尾数全0：表示0
// 阶码全1，尾数全0：表示∞
// 阶码全1，尾数不为全0：表示NAN
// float浮点数的真值：(-1)^s * 1.M * 2^(E-127)
// double浮点数的真值：(-1)^s * 1.M * 2^(E-1023)

/**
 -0.75转换为IEEE754的float
 -0.75 = -(0.11) = -(1.1)*2^-1
 s = -1
 r = -0000 0001 + 0111 1111 = 0111 1110
 M = 1000 0000 0000 0000 0000 000
 1 0111 1110 1000 0000 0000 0000 0000 000
 ----------------------------------------------------------------
 IEEE 754 C0 A0 00 00H表示多少？
 1100 0000 1010 0000 0000 0000 0000 0000
 s = 1
 r = 100 0000 1
 M = 010 0000 0000 0000 0000 0000 = 1.01
 真值 = 1000 0001 - 0111 1111 = 0000 0010 = 2
 -1.01*2^2 = -5.0
 ----------------------------------------------------------------
 IEEE754最小绝对值和最大绝对值
 最小绝对值：
 尾数全为0：1.0000....
 阶码最小值：-126
 最小值：1.0*2^-126
 最大绝对值：
 阶码：127
 尾数：1.11...23个1
 1.11...*2^27
 */

// ***** 浮点数的加减运算 *****
// 1.对阶：阶数小的向阶数大的对齐
// 2.尾数加减
// 3.规格化：M.xxx -> M不为0
// 4.舍入
// 5.判溢出：判断阶码是否溢出

/**
 例：已知十进制数X=-5/256、Y=+59/1024,按机器补码浮点运算规则计算X-Y,结果用二进制表示，
 浮点数格式如下：阶符取 2 位，阶码取 3 位，数符取 2 位，尾数取 9 位
 X = -101 * 2^-8 = -0.101 * 2^-5 = -0.101 * 2^(-101)
 Y = 111011 * 2^-10 = 0.111011 * 2^-4 = 0.111011 * 2^(-100)
 
 X阶码补码=11.011
 X尾数补码=11.011000000
 Y阶码补码=11.100
 Y尾数补码:00.111011000
 X:11.011,11.011000000
 Y:11.100,00.111011000
 
 1.对阶
 x的阶小，小阶向大阶对齐
 X:11.100,11.101100000
 
 2.尾数加减
  11.101100000
 +11.000101000
 ------------------------
  10.110001000
 X-Y=11.100,10.110001000
 
 3.规格化
 X-Y=11.101,11.011000100
 
 4.舍入：无
 5.判溢出：无
 
 X-Y=11.101,11.011000100
 -00.1001111*2^(-3)
 */

// 类型强制转换
// int转为float，会有精度损失
// float转为int，会有溢出或者精度损失

// ***** 算术逻辑单元 *****
// 串行加法器：一位一位的加
// 串行进位的并行加法器：多个加法器串联
// 并行进位的并行加法器：同时进位


// ***** 存储器 *****
// 【CUP > 寄存器 > 高速缓存 > 主存】 > 辅存 > 外存
//---MARK---
// 按存储介质分类
// 1.半导体：主存、Cache
// 2.磁：磁盘、磁带
// 3.光：光盘

// 按存取方式分类
// 1.随机存取：SSD
// 2.顺序存取：磁带（读取速度与位置有关）
// 3.直接存取：机械硬盘（读取速度与位置有关）

// 按信息可更改性分类
// 1.可读、可写
// 2.只读ROM（Read Only Memory）

// 按照信息可保存性分类
// 1.易失（主存，Cache）
// 2.非易失（辅存，光盘）

// 1.读取后，破坏信息DRAM
// 2.读取后，非破坏信息

// 存储器性能指标
// 1.存储容量 = 字长 * 字数
// 2.单位成本
// 3.存储速度

// ***** 主存储器的组成 *****
// 存储体+MAR+MDR
// 存储元：电容+MOS管
// 存储单元：存储元+存储元...
// 存储芯片的基本原理...

// 引脚数量
// 地址线 + 数据线 + 片选线 + 读写控制线

// 8kx8位存储芯片：2^13 * 8bit
// 8kx1位存储芯片：2^13 * 1bit
// 64kx16位存储芯片：2^16 * 16bit
// 存储单元数量（地址线） x 存储字长（数据线）

// 寻址
// 字长4B，总容量为1KB
//          单元   地址线   每单元
// 按字节寻址：1     10      1B
// 按字寻址 ：256    8      4B
// 按半字寻址：512   9      2B

// ***** SRAM和DRAM *****
// RAM：random access memory 随机存储
// DRAM：Dynamic 用于主存
// SRAM：Stable 用于高速缓存

// DRAM：栅极电容；
// 读取1：MOS管接通，电容放电
// 读取0：MOS管接通，电容无电流
// 破坏性读出，慢，成本低，体积小，集成度高
// 送行列地址：分2次

// SRAM：双稳态触发器；
// 读出1：XBL低电平
// 读出0：BL低电平
// 非破坏性读出，快，成本高，体积大，功耗大
// 送行列地址：1次送

// DRAM刷新
// 2ms刷新一次，每次刷新一行存储单元
// 行列地址：减少选通线数量

// 刷新方式：
// 行列：128*128，2ms刷新，读写周期为0.5us
// 1.分散刷新：0.5us读写、0.5us刷新
// 2.集中刷新：64us集中刷新
// 3.异步刷新：15.6us刷新一次

// ***** ROM芯片 *****
// 非易失性存取
// MROM：厂家只读芯片
// PROM：可编程只读
// EPROM：可擦除、可编程只读，UVEPROM、EEPROM
// Flash Memory：闪存U盘，写之前要先擦除，所以写慢读快
// SSD：固态硬盘
// BIOS芯片：自举装入程序

// ***** 主存储器与CUP连接 *****
// 存储芯片的输入和输出信号
// 地址线：A0,A1...表示
// 数据线：D0,D1...表示
// 片选线：CS(上划线)，低电平有效
// 读写控制线：WE（上划线），低电平写

// 位拓展-提高数据总线利用率
// 8位的CUP连接8个8kx1位的存储芯片
// 8kx1位：地址总共2^13，地址总线需要13个引脚
// 每次只能传输1位，数据总线利用的不充分，可以拓展8个芯片

// 字拓展-拓展地址
// 8位的CUP连接8个8kx8位的存储芯片
// 地址总共2^13，地址总线需要13个引脚
// 数据总线需要8个引脚，利用充分
// A13,A14地址总线连接片选线，有且只有1个高电平（线选法：地址不完整）01xxx, 10xxx合法；11xxx,00xxx非法；
// 使用1-2、2-4、3-8译码器进行字拓展（片选法：地址完整）

// ***** 双口RAM&多模块存储器 *****
// 存取周期：存取时间+恢复时间

// 双端口RAM--双核CPU同时对主存进行访问
// 1.两个端口对不同地址单元存取
// 2.两个端口对同一地址单元读
// 3.两个端口对同一地址单元写 出错
// 4.对同一地址单元，一个端口写，一个端口读 出错

// 多体并行存储器--单核CPU连续访问多个主存
// 1.高位交叉编址: xx... 从上到下
// 2.低位交叉编址: ...xx 从左到右,✨效率高
// xx来表示访问哪个存储体

/**
 4个存储体，假设存取时间为r，存取周期T=4r，低位交叉编址连续访问
 00000
 00001
 00010
 00011
 00100
 需要多少时间？
 甘特图得T+4r，访问连续的n个存储字：T+(n-1)r
 */

// 低位交叉编址：“流水线”
// 模块数m>=T/r

// ***** ✨Cache *****
// 空间局部性：指令、数据是顺序存储的
// 时间局部性：程序中存在大量循环结构
// 把目前访问的周围的数据放入Cache

// Cache命中率H
// Cache缺失率1-H
// 平均访问时间：tH + (1-H)(t+T)
// 同时在Cache和主存中查找：tH + (1-H)T

/**
 假设 Cache 的速度是主存的 5 倍，且 Cache 的命中率为 95%，则采用 Cache 后存储器性能提高多少（设 Cache 和主存同时被访问，若 Cache 命中则中断访问主存）?
 5t
 t*0.95 + 0.05*5t = 1.2t
 4.17倍
 ------------------------------------------------
 若先访问Cache再访问主存，性能提升多少？
 5t
 0.95t + 0.05*6t=1.25t
 4倍
 */
// Cache如何与主存映射？
// Cache满了怎么办？
// Cache如何与主存保持一致？

// ***** Cache映射 *****

// 1.全相联映射：空间利用充分，慢
// 2.直接映射：空间利用不充分，快
// 3.组相连映射：综合

// 全相联映射（随意放）
// 有效位 标记 Cache
// 标记位数 = 主存块号位数
/**
 主存地址空间大小为256MB；有8个Cache行，行长为64B；
 主存地址：28位表示
 Cache块：6位表示
 ----------------------------
 主存块号：22位表示
 主存块内：6位表示
 Cache标记位：22位，等于主存块号
 Cache有效位：1表示占用，0表示空闲
 */

// 直接映射（主存块%Cache块总数）
// 有效位 标记 Cache
// 标记优化：
// 令Cache块总数=2^n
// 位数-=n，后n位=Cache块号

// 组相连映射（主存块号%分组数）
// 有效位 标记 Cache
// 把Cache分为n组
// 标记优化：
// 位数-=n
// n路组相连：n行作为1组

// ***** Cache替换算法 *****
// 1.随机算法RAND：未考虑局部性
// 2.先进先出FIFO：未考虑局部性
// ✨3.近期最少使用LRU：考虑局部性
// 命中时，命中计数器设为0，比其低的计数器+1
// 未命中，未满，加入Cache，其余计数器+1
// 未命中，满，删除最大计数器
// 4.最近不经常使用LFU：未考虑局部性
// 删除最小计数器

// ***** Cache写 *****
// 写回法（替换时同步）
// 有效位 脏位 标记 Cache
// 替换时，脏位=1说明Cache被写过。往主存中写数据

// 全写法（实时同步）
// 同时写Cache和主存，慢
// 优化：CPU往写缓冲里写

// 未命中时的写
// 写分配法（配合写回法）：调入Cache
// 非写分配法（配合全写法）

// 多级Cache
// Cache间：全写法+非写分配法

// ***** 页式存储器 *****
// 页式存储
// 把进程分割成大小相等的页面，离散的放入存储器中

// 逻辑地址：程序员看见的地址
// 物理地址：主存中的实际地址

// 映射：使用页表
// 逻辑页号  块号
// #1       3
// #2       8
// #3       3648
// #4       4082

// 页表的储存位置
// 存在主存中，每一次都需要进行访存操作

// 快表TLB
// 访问页表后，把页表的一项加入快表中


// ***** 系统指令 *****
// 零地址指令
// 1.不需要操作数的指令如关机，关中断
// 2.操作数隐藏的指令如操作数隐藏在栈顶

// 一地址指令
// 1.++，--，求反码、补码
// 2.一个操作数隐藏在寄存器中的指令

// 二地址指令
// A OP B -> A

// 三地址指令
// A OP B -> C

// 四地址指令
// A OP B -> C + NextAddress

// 指令字长可变
// 操作码长可变

// ***** 拓展操作码 *****

// 指令字长16位，每个地址码占4位
// 1.3地址指令 15个
// 操作码：0000~1110 地址 + 地址 + 地址
// 2.2地址指令 15个
// 操作码：1111 0000~1110 地址 + 地址
// 3.1地址指令 15个
// 操作码：1111 1111 0000~1110 地址
// 4.零地址指令 16个
// 操作码：1111 1111 1111 0000~1111

// 频率高的指令，设计更短的操作码

// ✨指令字长固定为16位，设计一套指令满足
// 1.15条三地址指令
// 2.12条二地址指令
// 3.62条一地址指令
// 4.32条零地址指令

// 0000-1110 + 地址 + 地址 + 地址 16个三地址
// 1111 0000-1011 地址 + 地址 12个二地址

// 1111 1100 0000-1111 地址 16个一地址
// 1111 1101 0000-1111 地址 16个一地址
// 1111 1110 0000-1111 地址 16个一地址
// 1111 1111 0000-1101 地址 14个一地址

// 1111 1111 1110 0000-1111 16个零地址
// 1111 1111 1111 0000-1111 16个零地址

// ***** 指令寻址 *****
// 指令 = 操作码（OP） + 地址码
// PC = program counter

// 顺序寻址：每一次PC指向下一条指令
// 跳跃寻址：由转移指令指出跳转位置：PC -> JUMP 7

// ***** 数据寻址 *****
// 指令 = 操作码OP + 地址码A = LOAD A
// 数据寻址：找到地址码的真实地址

// 直接寻址：取指令，取数据 2次访存
// 优点：简单
// 缺点：不灵活

// 间接寻址：取指令，取真实地址，取数据 3次访存
// 优点：扩大了寻址范围，便于汇编
// 缺点：需要多次访存

// 寄存器寻址 取指令 1次访存
// 优点：速度快
// 缺点：贵

// 寄存器间接寻址 取指令，取数据 2次访存
// 隐含寻址

// 立即寻址 取指令，值就在指令中 1次访存
// 优点：访存少
// 缺点：A的值范围小

// ***** 数据寻址2 *****

// 基址寻址
// CPU中有BR寄存器，只能由操作系统确定
// 从程序的起始位置开始

// 变址寻址
// IX寄存器记录起始地址（偏移量），可以被程序员修改
// 方便循环程序

// 相对寻址
// 基于下一条指令的位置

// ***** 数据寻址3 *****

// 堆栈寻址
// SP堆栈寄存器 = Stack Pointer
 
// 硬堆栈：在寄存器中堆栈（成本高，速度快）
// 软堆栈：在主存中堆栈（经济实惠）

// ***** CISC&RISC *****
// CISC复杂指令集：x86，笔记本台式机
// RISC精简指令集：ARM架构，手机平板

// RISC只有LOAD和STORE指令可以访存
// RISC有较多寄存器
// RISC可以通过优化编译来使程序更高效


// ***** 中央处理器 *****

// ***** CPU功能和结构 *****

// 功能
// 1.指令控制
// 2.操作控制
// 3.时间控制
// 4.数据加工
// 5.中断处理

// CPU = 运算器 + 控制器
// 运算器：对数据加工
// 控制器：取指令、分析指令、执行指令、中断处理

// ***** CPU指令执行过程 *****
// 指令周期：【取指令+分析指令】+执行指令

// 取指周期
// 1.指令地址放入地址寄存器中：(PC)->MAR
// 2.CU发出读信号：1->R
// 3.读取数据：M(MAR)->MDR
// 4.指令放入IR：(MDR)->IR
// 5.CU控制PC指向“下一条”指令：PC + "1" -> PC

// 间址周期
// 1.IR中的地址放入MAR：Ad(IR)->MAR
// 2.CU发出读信号：1->R
// 3.读取数据：M(MAR)->MDR
// 4.传送地址：(MDR)->Ad(IR)

// 中断周期
// 堆栈来保存中断前的地址
// 1.SP-1后，把地址放入MAR: (SP)-1->SP,(SP)->MAR
// 2.CU发出写信号：1->W
// 3.(PC)->MDR
// 4.让PC指向系统调用：向量地址->PC

// ***** ✨数据通路功能 *****

// 单总线方式
// 1.寄存器之间的数据传送
// 把PC的数据放入MAR
// (PC)->BUS PCout有效，PC内容放入总线
// BUS->MAR MARin有效，总线内容放入MAR

// 2.主存与CPU之间的数据传送
// (PC)->BUS->MAR PCout和MARin有效
// 1->R 发送读命令
// M(MAR)->MDR MDRinE（外部数据线流入）
// MDR->BUS->IR MDRout和IRin有效

// 3.执行算数运算或者逻辑运算
// 1.Ad(IR)->BUS->MAR IRout和MARin有效
// 2.1->R 发送读信号
// 3.M(MAR)->BUS->MDR MDRin有效
// 4.MDR->BUS->Y, MDRout和Yin有效
// 5.(Y)+(ACC) -> Z, ACCout和ALUin有效，CU给ALU发送加法信号
// 6.Z->ACC, Zout和ACCin有效

// ***** 硬布线控制器 *****

// 取指周期FE=1
// 间指周期IND=1
// 执行周期EX=1
// 中断周期INT=1

// 一个节拍内，可以并行完成多个微操作
// 同一个微操作可能在不同阶段使用
// 不同指令的时间周期不同，为了简化电路，以最大节拍为准

// 执行周期
// 1.ACC清零：0 -> AC
// 2.取数：Ad(IR)->MAR
// 1->R
// M(MAR) -> MDR
// MDR -> AC
// 3.JUMP X: Ad(IR)->PC
// 4.BAN X:A0*Ad(IR) + !A0*PC ->PC(如出现负数，把IR放入PC，否则不改变PC)

// 微操作原则
// 1.顺序不得随意改
// 2.不同对象一节拍
// 3.时间较短一节拍

// ***** ✨微程序控制器 *****

// 微程序设计思想：一条机器指令写成一个微程序。微程序包含多条微指令
// 程序由多条指令组成
// 微程序由多条微指令组成

// 指令：程序的执行描述
// 微指令：指令的执行描述
// 微操作（微命令）：描述指令的执行

// 微程序控制器结构
// CM：控制存储器，存放各指令的微程序，是ROM
// CMAR：CU中的地址寄存器，别名：μPC
// CMDR：存储微指令，别名：μIR
// 地址译码器：生成控制信号
// 微地址形成部件：确定微指令首地址
// 顺序逻辑

// ✨取指周期通常是公用的，如果程序中有n条机器指令，则CM中至少有n+1个微程序
// ✨一条指令对应一个微程序

// ***** 微指令的设计 *****

// 相容性的微命令：可以并行的微命令
// 互斥性的微命令：不可以并行的微命令

// ✨水平型微指令：一条微指令可以并行多个微命令
// 优点：程序快，微程序短
// 缺点：微指令长，编写程序复杂

// ✨垂直型微指令：一条微指令对应一条微命令
// 优点：微指令短，简单
// 缺点：执行速度慢，微程序长

// 混合型微指令：在垂直型的基础上，增加不复杂的并行操作

// ✨微指令的编码方式
// 1.直接编码
// 某一位为“1”表示该控制信号有效
// 优点：简单直观，速度快
// 缺点：n个微指令需要n个字段，导致控存容量大

// 2.字段直接编码
// 要留出一个状态，表示不操作
// 互斥性微命令放在同一字段内
// 相容性微命令放在不同字段内
// 优点：可以缩短微指令字长
// 缺点：每次都需要译码器译码，速度慢于直接编码
/**
 算机的控制器采用微程序控制方式，微指令中的操作控制字段采用字段直接编码法，共有 33 命令
 构成 5 个互斥类，分别包含 7、3、12、5 和 6 个微命令，则操作控制字段至少有多少位？
 因为需要用1个状态表示不操作，所以每个互斥类表示的微命令为：
 8、4、13、6、7
 需要的位数：
 3+2+4+3+3=15
 ------------------------------------------
 若采用直接编码，需要的控制字段位数为？
 7+3+12+5+6=33
 */

// 微指令的下地址
// ✨1.段定方式：存放在字段中
// 2.根据机器指令的操作码形成
// ✨3.增量计数法：(CMAR) + 1 -> CMAR
// 4.分支转移：类似JUMP
// 5.通过测试网络
// 6.由硬件产生

/**
 某计算机采用微程序控制器，共有 32 条指令，公共的取指令微程序包含 2 条微指令，各指令对应的微程序平均由 4 条微指令组成，采用断定法（下地址字段法）确定下条微指令地址，则微指令中下地址字段的位数至少是多少位？
 32*4+2 = 130
 2^8 = 256，所以至少8位
 */

// ***** 微程序控制单元的设计 *****

// 微程序控制器：CISC CPU（复杂指令集CPU）
// 好维护
// 硬布线控制器：RISC CPU（精简指令集CPU）
// 重点图...

// ***** 指令流水线 *****

// 1.顺序执行方式
// 取值、分析、执行时间都为t：总时间3nt
// 硬件开销小，但是利用率低

// 2.一次重叠方式
// 3t+2t*(n-1) = (1+2n)t
// 硬件部件开销大，执行时间明显缩短

// 3.两次重叠
// 3t+(n-1)t = (2+n)t

// 流水线性能指标
// 1.吞吐率：单位时间完成任务的数量
// 2.加速比：顺序执行时间 / 流水线执行时间
// 3.效率：设备利用率；

// ***** 指令流水线影响因素 *****

// ✨五段式流水线：IF取指、ID析指、EX执行、M存储、WB写回
// 取指、分析、执行、访存、写回阶段的周期应该统一

// IF取指、ID析指、EX执行、M存储、WB写回。
// 1、100ns、80ns、70ns、50ns、60ns，以最长时间为准，设机器周期为100ns。
// 2、锁存器：保证周期统一，应该把数据保存在锁存器中，等待机器周期。
// 3、IF Cache 和 M Cache是两个独立的Cache，这使得IF和M可以并行的运行。
// 4、ID从通用寄存器中取数，并放入A、B锁存器。
// 5、EX通过ALU运算A和B；Imm=立即数；结果放入锁存器。
// 6.W保存数据
// 7.WB可能把结果写入通用寄存器中。

// ✨影响流水线的因素
// 1.结构相关：资源互斥
// 解决方法：1）后面的指令暂停1个周期
// 2）资源重复配置：数据存储器+指令储存器

// ✨2.数据相关：数据同步
// 解决方法：1）硬件阻塞等待；软件执行”nop“空指令
// 2）数据旁路技术（又称为”转发机制“）
// 3）编译优化：把后续的不相干的指令先提前执行

// 3.控制相关
// 条件语句使得PC的指向发生改变
// 解决方法：1）永远猜true或者动态调整猜测
// 2）预取true和false指令
// 3）提前形成条件码
// 4）提高转移方向的准确率

// 流水线的多发技术
// 1.超标量技术：独立并发多条指令，不能调整顺序
// 2.超流水技术：一个时钟周期再分段，一个周期内一个部件使用多次，不能调整顺序
// 3.超长指令字：多条可以并行操作的指令组合成一条

// ***** 五段式指令流水线 *****

// 在RISC精简指令集中，只有LOAD和STORE指令需要访存。

// 运算类指令
// IF：根据PC从指令Cache中取出指令放入锁存器
// ID：从寄存器中取数存入锁存器
// EX：运算，将结果存取锁存器
// M：空段
// WB：将运算结果写回指定寄存器

// LOAD指令
// IF：根据PC从指令Cache中取指令，放入锁存器中。
// ID：将基地址存入寄存器A，将偏移量存入Imm中。
// EX：计算地址，放入锁存器。
// M：从Cache中取数，放入锁存器中。
// WB：将结果写入指定寄存器。

// STORE指令
// IF：根据PC从指令Cache中获取指令，放入锁存器中。
// ID：将基地址存入寄存器A，将偏移量存入Imm，将要存的数存入寄存器B。
// EX：运算得到真实地址，并将B放入store锁存器中。
// M：写入数据Cache
// WB：空段

// 条件转移指令
// IF：根据PC从指令Cache中获取指令，放入锁存器中
// ID：需要比较的数放入锁存器，偏移量放入Imm中
// EX：运算比较大小
// M：将PC的值写回PC
// WB：空段

// 无条件转移
// IF：根据PC从指令Cache中取出指令，放入锁存器
// ID：将偏移量放入Imm
// EX：将PC值写回PC
// M：空段
// WB：空段

// 条件转移指令的执行过程
// 不转移：(PC) + 指令字长 -> PC
// (PC) + 指令字长 + (偏移量*指令字长) -> PC


// ***** 总线 *****
// 每个总线由很多信号线组成，所以一次可以传输n个bit数据
// 同一时刻，只能有1个部件发送数据，可以多个部件都能收到数据

// 总线的特性
// 1.机械特性：尺寸，形状，管脚数
// 2.电器特性：传输方向和有效电平范围
// 3.功能特性：传输线的功能（地址、数据、控制）
// 4.时间特性

// ✨总线的分类
// 串行总线：每次可以传1位
// 例子：USB
// 优点：只需要1条传输线，成本低，抗干扰能力强。广泛应用于长距离传输
// 缺点：发送和接收时，需要装配和拆卸

// 并行总线：每次可以传n位
// 优点：总线的逻辑时序简单，电路实现简单
// 缺点：造价高，抗干扰能力弱，不适合长距离传输

// =======================================
// 片内总线：CPU芯片内部，某些部件间的总线

// ✨系统总线：连接计算机系统中各部件的总线
// 又可以分为：数据总线，地址总线和控制总线
// 数据总线：数据总线中的信号线 = 机器字长时，只需要一次传输就能获得CPU能处理的数据
// 地址总线：单向的，地址总线位数，与主存地址空间大小有关
// 控制总线

// 通信总线：连接计算机的总线

// =======================================
// 单总线结构：CPI、主存、IO等都连接在一组总线上
// 优点：结构简单，成本低
// 缺点：带宽低、负载重、多部件争抢一条总线

// 双总线结构
// CPU、主存、通道连接在主存总线上
// （通道：阉割版的CPU，专门管理IO设备）
// IO设备和通道连接在IO总线上
// 优点：将慢速的IO设备从主存总线上分离，支持突发传送（指明一个地址，获取多个地址的数据）
// 缺点：需要增加通道等硬件设备

// 三总线结构
// CUP和主存使用主存总线连接
// 主存和快速IO用DMA总线连接
// CPU和慢速IO通过IO总线连接
// 优点：提高了快速IO设备的效率
// 缺点：系统的效率低

// =======================================
// ✨性能指标
// 1.总线周期
// 申请阶段、寻址阶段、传输阶段、结束阶段

// 2.总线时钟周期
// 即机器时钟周期

// 3.工作频率
// 1秒多少个总线周期

// 4.时钟频率
// 1秒多少个总线时钟周期

// 5.总线宽度
// 可以同时传输多少个数据位

// 6.总线带宽（最高传输速率）
// 每秒可以传输多少信息

// 7.总线复用
// 地址、数据总线分时复用

// 8.信号线数
// 所有总线的信号线数

/**
 例.某同步总线采用数据线和地址线复用方式,其中地址/数据线有32根,总线时钟频率为 66MHz，每个时钟周期传送两次数据（上升沿和下降沿各传送一次数据）。
 1) 该总线的最大数据传输率（总线带宽）是多少？
 2) 若该总线支持突发（猝发）传输方式，传输一个地址占用一个时钟周期，则一次
 “主存写”总线事务传输 128 位数据所需要的时间至少是多少？
 
 1) 每个时钟周期传送两次数据总线工作频率是时钟频率的两倍
 总线工作频率=2×66MHz=132MHz
 总线宽度=32bit=4B
 总线带宽=总线工作频率×总线宽度=132×4MB/s=528MB/s

 2) 突发（猝发）传输方式：一次总线事务中，主设备只需给出一个首地址，从设备就能 5 从首地址开始的若干连续单元读出或写入多个数据。
 发送首地址占用 1 个时钟周期，128位数据需传输4次， 占用2个时钟周期
 个时钟周期=1/66MH≈15ns 总耗时=(1+2)×15ns=45ns
 */

// ***** ✨总线的仲裁 *****
// 主设备：获得总线控制权的设备
// 从设备：响应主设备的设备

// 工作流程
// 1.主设备请求总线
// 2.若多个主设备同时申请，CPU判优（集中仲裁）
// 3.主设备获得总线的控制权

// BR请求信号
// BG允许信号
// BS总线忙

// 链式查询方式：BR、BG、BS
// 物理串联，离总线控制权越近，优先级越高
// 优点：优先级固定，结构简单
// 缺点：对硬件的故障敏感，优先级低的设备可能长时间无法使用总线

// 计数器查询方式：BR，BS，设备地址线
// 优点：1.计数器从上一个设备开始，总线的控制权相对公平
// 2.电路故障没有链式查询敏感
// 缺点：控制线的数量增加了：n个设备，需要控制线: log2n + 2
// 控制相对链式查询复杂

// 独立请求方式：每个设备都有BR、BG；BS
// 每个设备都有一根BR和BG
// 优点：响应速度快，不必在设备间查询；优先级非常灵活
// 缺点：控制线的数量很多2n+1条控制线；控制逻辑更加复杂

// 分布式仲裁方式
// 每个设备都有仲裁器，将自己的仲裁号发送到仲裁总线上
// 各个设备各自判断优先级，仲裁号低的自觉取消仲裁号

// ***** 总线的操作和定时 *****
// 占用总线的一对设备，如何使用电信号完成数据传输？

// 总线周期的四个阶段
// 1.申请分配阶段（总线仲裁）
// 2.寻址阶段：主设备发出从地址和命令
// 3.传输阶段：单向和双向传输
// 4.结束阶段：让出总线

// 总线定时：一种协议或者规则

// 同步定时方式（统一的定时信号）
// 若干个时钟产生相等的时间间隔，每个间隔构成一个总线周期
// 优点：传送速度快，总线逻辑简单，适合部件存取时间接近的设备
// 缺点：属于强制同步，不对数据进行验证，可靠性差

// 异步定时方式
// 不互锁：请求信号、回答信号一段时间后主动撤销
// 半互锁：请求信号收到回答信号才撤销
// 全互锁：请求信号收到回答信号才撤销；请求信号撤销后，回答信号才撤销
// 优点：总线周期长度可变，工作速度相差大的部件之间可以可靠交换信息
// 缺点：比同步控制复杂，速度比同步控制慢

// ***** 总线标准 *****
// 协议和标准

// 根据位置进行分类
// 系统总线：CPU直接连接，CPU连接北桥芯片，CPU连接主存
// 局部总线：不与CPU之间连接，北桥芯片与显卡、声卡
// 设备总线：由南桥芯片控制，连接外部I/O（慢速）

// ✨Industry Standard Architecture
// ✨ISA标准：系统总线
// ✨EISA标准：系统总线
// ✨PCI标准： 并行局部总线
// ✨PCI-E标准：串行局部总线
// ✨USB：设备总线、串行；
// 热插拔，可以连接127个外设

// RS-232C：串行设备总线
// SCSI：并行
// PCMCIA：并行设备总线；存储卡
// IDE（ATA）：并行硬盘总线
// SATA：串行硬盘总线


// ***** IO系统概念 *****
// IO设备可以统称为“外部设备”

// IO接口（集成在主板上）
// 又称为IO控制器，负责主机和设备间的数据传输
// 数据寄存器：IO数据
// 控制寄存器：控制外设
// 状态寄存器：外部设备的状态（打印机状态）

// 如何控制键盘IO的完成？
// 1.程序轮询...
// 2.程序中断方式：键盘输入后，IO接口发出中断请求，CPU读数据。
// 数据流：键盘→IO接口的数据寄存器→数据总线→CPU寄存器→主存

// 对于磁盘的IO如何控制？
// 程序中断方式：导致CPU会花很多时间处理中断请求，降低效率...
// DMA接口（也是IO接口）：Direct Memory Access
// CPU给DMA指定：主存地址、磁盘地址、读写数据量
// DMA每完成一块的读写（如1KB），才发出中断请求

// 通道控制方式
// 商用大型机器上可能接很多IO设备，若都让CPU来处理，则会影响CPU的效率。
// 通道能对IO设备进行统一的管理（弱鸡版的CPU）

// 1.CPU向通道发出IO指令，指明IO程序的地址
// 2.通道执行内存中的指令
// 3.完成任务后向CPU发出中断请求

// IO指令：CPU执行的指令，控制IO接口或者通道
// 通道指令：通道执行的指令

// ***** 外部设备 *****

// ✨VRAM
// 显存，刷新存储器，必须把一帧图像的信息存放在显存中。
// VRAM容量 = 分辨率 * 灰度级
// VRAM带宽 = 分辨率 * 灰度级 * 帧频

// ✨磁盘存储器
// 每个盘面对应一个磁头
// 每个盘面上有多个磁道（年轮）
// 柱面：所有盘面相同位置的磁道
// 扇区：对磁道的划分，磁盘的读写以扇区为单位

// 格式化容量：磁盘总容量 - 备用容量
// 非格式化容量：磁盘总容量

// 道密度：60道/cm：可以算出盘面上有多少个磁道
// 位密度：600b/cm：单位长度可记录二进制
// 每个扇区可以储存的位数相同：内侧位密度 > 外侧位密度
// 面密度：位密度 * 道密度

// ✨平均存取时间
// 寻道时间（磁头移动） + 旋转延迟时间 + 传输时间

// 磁盘的读写诗串行的，每次只能读写1比特数据

// ✨RAID 磁盘阵列
// RAID0：逻辑上相邻的扇区，保存在不同的磁盘中；没有容错能力
// RAID1：镜像磁盘阵列；有容错能力，容量减少一半
// RAID2：采用纠错的海明校验码的磁盘阵列

// ***** I/O接口 *****

// I/O接口的工作原理
// 控制寄存器（启动打印机）
// 数据寄存器（写入需要打印的数据）
// 状态寄存器（判断设备工作是否完成）

// 统一编址（和主存一起编址）
// 优点：电路简单，灵活性高，有较大编址空间
// 缺点：占用主存地址空间，寻址时间长

// 独立编址
// 优点：设置专门I/O指令，程序编址清晰；IO端口位数少，寻址速度快；不占用主存空间
// 缺点：I/O指令少，程序灵活性差；需要区别存储器和I/O设备，增加电路复杂性。

// ***** ✨I/O方式：程序查询方式 *****
// 轮询：准备就绪？No -> 查询状态 -> 准备就绪？No -> 查询状态...
// 优点：IO接口设计简单
// 缺点：CPU利用率低

// 定时查询：每隔一段时间查询一次
// 独占查询：100%的时间都在查询

/**
 在程序查询方式的输入/输出系统中,假设不考虑处理时间,每一个查询操作需要100个时钟周期 CPU 的时钟频率为 50MHz。
 现有鼠标和硬盘两个设备，而且CPU必须每秒对鼠标进行30次查询,硬盘以32位字长为单位传输数据,即每32位被CPU查询一次,传输率为2×2^20B/s。求CPU对这两个设备查询所花费的时间比率，由此可得出什么结论？

 一个时钟周期长度为：1 / 50M s = 0.02 * 10-6s = 20ns
 一次查询：20ns * 100 = 2000ns
 
 每秒对鼠标的查询时间：2000 * 30 = 60000ns
 查询时间占比：60000ns / 1s = 0.006%
 
 每秒对硬盘的查询次数：2*2^20B / 4B = 2^19
 查询时间占比：2^19 * 2000ns / 1s = 105%
 CPU不可能完成这个速度！
 
 结论：对于慢速的IO设备，可以使用程序查询的方式。（定时查询）
 */

// ***** ✨I/O方式：程序中断方式 *****
// 基本概念：
// 1.中断请求
// 向CPU发出中断请求（关中断状态下不理睬）
// 2.中断响应
// CPU每条语句后都会进行中断判优，判断执行哪个中断
// 3.中断处理

// 非屏蔽中断（如：掉电）
// 可屏蔽中断：关中断时，不理睬（大部分中断）

// 中断判优
// 硬件中断 > 软件中断
// 非屏蔽中断 > 屏蔽中断
// DMA > I/O
// 高速设备 > 慢速设备
// 输入 > 输出
// 实时设备 > 普通设备

// ✨ 中断隐指令：关中断；保存原程序的PC；让PC指向中断的第一条指令；
// 如何保存？保存在何处？：内核堆栈
// 中断第一条指令在哪里？：硬件产生向量地址，再由向量地址找到入口地址

// 单重中断

// ***** 多重中断（套娃） *****
// 中断屏蔽字：屏蔽某些中断请求（高速设备使用时，屏蔽低速设备）
// 屏蔽字=1 说明屏蔽该中断；屏蔽字=0 说明会被该中断中断
// 自身的屏蔽字=1

/**
 D>A>C>B
 中断源    屏蔽字
       A    B    C    D
   A       1    1     1    0
   B       0    1     0    0
   C       0    1     1    0
   D       1    1     1    1
 */

// ***** DMA方式 *****
// 用于高速设备，有专门的DMA控制器，它也属于一种IO控制器。
// DMA控制器通常用来控制磁盘，等快速设备
// CPU向DMA指明要输入还是输出；要传输多少数据；数据在主存和外设的地址；
// DMA传输完一个字的数据后，再向CPU发出中断请求。

// 系统总线+DMA总线结构
// 1.DMA传输时，停止CPU：控制简单
// 2.DMA总线和系统总线，时间交替访问主存：不需要总线使用权的申请
// 3.周期挪用
// CPU正在访存时，存取周期结束后，让出主存
// CPU和DMA同时访问时，CPU让出主存

#endif /* computer_hpp */
